package com.varian.system.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.varian.log.model.ApiLogger;
import com.varian.mybatis.base.BaseServiceImpl;
import com.varian.mybatis.util.PageUtil;
import com.varian.system.constant.SystemConstant;
import com.varian.system.convert.SystemConvert;
import com.varian.system.dto.ApiErrorLogHandleDTO;
import com.varian.system.dto.ApiLogPageDTO;
import com.varian.system.entity.ApiErrorLog;
import com.varian.system.entity.ApiLog;
import com.varian.system.mapper.ApiErrorLogMapper;
import com.varian.system.mapper.ApiLogMapper;
import com.varian.system.service.IApiLogService;
import com.varian.system.vo.ApiLogItemVO;
import com.varian.system.vo.ApiLogVO;
import com.varian.tool.exception.BizException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

/**
 * @author ben
 * @since 2024/7/23
 */
@Service
@RequiredArgsConstructor
public class ApiLogServiceImpl extends BaseServiceImpl<ApiLogMapper, ApiLog> implements IApiLogService {

    private final SystemConvert baseConvert;
    private final ApiErrorLogMapper apiErrorLogMapper;

    @Override
    public Page<ApiLogItemVO> page(ApiLogPageDTO dto) {
        Page<ApiLog> page = baseMapper.selectPage(dto.toPage(), lambdaQuery().getWrapper()
                .likeRight(StrUtil.isNotEmpty(dto.getTraceId()), ApiLog::getTraceId, dto.getTraceId())
                .eq(StrUtil.isNotEmpty(dto.getRequestMethod()), ApiLog::getRequestMethod, dto.getRequestMethod())
                .eq(StrUtil.isNotEmpty(dto.getServerName()), ApiLog::getServerName, dto.getServerName())
                .eq(dto.getHttpStatus() != null, ApiLog::getHttpStatus, dto.getHttpStatus())
                .le(dto.getEndTime() != null, ApiLog::getCreateTime, dto.getEndTime())
                .ge(dto.getStartTime() != null, ApiLog::getCreateTime, dto.getStartTime())
                .orderByDesc(ApiLog::getId));
        return PageUtil.convert(page, baseConvert::toVO);
    }

    @Override
    public ApiLogVO detail(Long id) {
        ApiLog apiLog = baseMapper.selectById(id);
        Assert.notNull(apiLog, () -> BizException.of(SystemConstant.API_LOG_NOT_EXIST));
        ApiErrorLog apiErrorLog = apiErrorLogMapper.selectOne(Wrappers.<ApiErrorLog>lambdaQuery()
                .eq(ApiErrorLog::getTraceId, apiLog.getTraceId()));
        return baseConvert.toVO(apiLog, apiErrorLog);
    }

    @Override
    public boolean saveApiLog(ApiLogger apiLogger) {
        ApiLog apiLog = baseConvert.toEntity(apiLogger);
        return save(apiLog);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveApiErrorLog(ApiLogger apiErrorLogger) {
        ApiLog apiLog = baseConvert.toEntity(apiErrorLogger);
        if (save(apiLog)) {
            ApiErrorLog apiErrorLog = new ApiErrorLog();
            apiErrorLog.setTraceId(apiErrorLogger.getTraceId())
                    .setTraceId(apiErrorLogger.getTraceId())
                    .setExceptionClass(apiErrorLogger.getExceptionClass())
                    .setExceptionLocal(apiErrorLogger.getExceptionLocal())
                    .setExceptionMessage(apiErrorLogger.getExceptionMessage())
                    .setStackTrace(apiErrorLogger.getStackTrace());
            apiErrorLogMapper.insert(apiErrorLog);
        }
        return true;
    }

    @Override
    public boolean errorHandle(Long id, ApiErrorLogHandleDTO dto) {
        ApiLog apiLog = baseMapper.selectById(id);
        Assert.notNull(apiLog, () -> BizException.of(SystemConstant.API_LOG_NOT_EXIST));
        ApiErrorLog apiErrorLog = apiErrorLogMapper.selectOne(Wrappers.<ApiErrorLog>lambdaQuery().eq(ApiErrorLog::getTraceId, apiLog.getTraceId()));
        Optional.ofNullable(apiErrorLog).ifPresent(errorLog -> {
            errorLog.setHandlingRemark(dto.getHandlingRemark())
                    .setHandlingStatus(dto.getHandlingStatus());
            apiErrorLogMapper.updateById(errorLog);
        });
        return true;
    }
}
